package ezeye.util;

import java.util.concurrent.locks.ReentrantLock;

public class EyeBuffer {
    public byte[] mBuffer = null;
    public int mPosRead = 0;
    public int mPosWrite = 0;
    public ReentrantLock mLocker = null;
    public boolean mNeedCompact = false;
    
    public EyeBuffer(int size) {
        assert(size > 0);
        mBuffer = new byte[size];
        mLocker = new ReentrantLock();
        mPosRead = 0;
        mPosWrite = 0;
        mNeedCompact = false;
    }
    
    public byte[] array() {
        return mBuffer;
    }
    
    public int capacity() {
        if (null != mBuffer)
            return 0;
        
        int length = mBuffer.length;
        return length;
    }
    
    public int posRead() {
        return mPosRead;
    }
    
    public void setPosRead(int pos) {
        mPosRead = pos;
        
        if (mPosRead < 0)
            mPosRead = 0;
        
        if (mPosRead > mPosWrite)
            mPosRead = mPosWrite;
    }
    
    public int posWrite() {
        return mPosWrite;
    }
    
    public void clear() {
        mPosRead = 0;
        mPosWrite = 0;
        mNeedCompact = false;
    }
    
    public void lock() {
        if (null == mLocker)
            return;
        
        mLocker.lock();
    }
    
    public boolean trylock() {
        if (null == mLocker)
            return false;
        
        boolean suc = mLocker.tryLock();
        return suc;
    }
    
    public void unlock() {
        if (null == mLocker)
            return;
        
        mLocker.unlock();
    }
    
    public boolean canWriteMore(int size) {
        if (size <= 0)
            return false;
        
        if (null == mBuffer)
            return false;
        
        int maxLen = mBuffer.length;
        int newPosWrite = (mPosWrite + size);
        if (newPosWrite > maxLen || newPosWrite <= 0)
            return false;
        
        return true;
    }
    
    public boolean write(byte[] data, int offset, int size) {
        if (null == data || offset < 0 || size <= 0 || (offset + size) > data.length)
            return false;
                
        boolean canWrite = canWriteMore(size);
        if (!canWrite)
            return false;
        
        System.arraycopy(data, offset, mBuffer, mPosWrite, size);
        
        mPosWrite += size;
        return true;
    }
    
    public void compact() {
        if (null == mBuffer)
            return;
        
        int remaining = mPosWrite-mPosRead;
        if (remaining > 0) {
            System.arraycopy(mBuffer, mPosRead, mBuffer, 0, remaining);
            mPosWrite = remaining;
            mPosRead = 0;
        } else {
            mPosWrite = 0;
            mPosRead = 0;
        }
        
        mNeedCompact = false;
    }
    
    public boolean needCompact() {
        if (null == mBuffer)
            return false;
        
        if (mNeedCompact)
            return true;
        
        boolean result = (mPosRead > (mBuffer.length/2));
        return result;
    }
    
    public void setNeedCompact(boolean val) {
        mNeedCompact = val;
    }
}
